﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Segmentator.IntegrityThroughInterval
{
    /**
     * Принятым упорядоченным по убыванию
     * однородным цепям считает минимумм симметрии текста по с использованием
     * однородных и разнородных цепей через минимизацию объема текста.
     */
    class UMChainCapacity:MinSymmetry
    {
        public override double Min(Intervals interval)
        {
            double H1 = 0, H2 = 0;
            double m, n1;

                m = interval.Count;
                n1 = interval.ElementAt(0).Count;

                 H1 = m * capacityGo(interval);  // умножаемое - мощность алфавита
                 H2 =  n1 * capacityGm(interval); // умножаемое - число самых частых сообщений
            return (H1 + H2);
        }

        /**
         * Объем по меронам
         */

        public double capacityGm(Intervals interval)
        {
            double[] Vi = new double[interval.ElementAt(0).Count];
            double reducer = 1;
            double G = 1;

            initArray(Vi);

            for (int i = 0; i < Vi.Count(); i++)// число миронов
            {
                for (int j = 0; j < interval.Count; j++)
                {
                    if (i > interval.ElementAt(j).Count - 1) continue;
                    reducer = (double) Math.Log(interval.ElementAt(j).ElementAt(i));                    
                    Vi[i] = Vi[i] * reducer;
                }
            }

            G = GetG(Vi, G);

            return G;
        }

        /**
         * Объем по таксонам
         */

        public double capacityGo(Intervals interval)
        {
            double[] Vi = new double[interval.Count];
            double G = 1;
            double reducer = 1;
                initArray(Vi);

            for (int i = 0; i < Vi.Count(); i++)
            {
                for (int j = 0; j < interval.ElementAt(i).Count; j++)
                {
                    reducer = Math.Log(interval.ElementAt(i).ElementAt(j));
                    Vi[i] = Vi[i] * reducer;
                }
            }

            G = GetG(Vi, G);

            return G;
        }

        private double GetG(double[] Vi, double G)
        {
            for (int i = 0; i < Vi.Count(); i++)
            {
                G = Vi[i] * G;
            }

            G = Math.Pow(G, 1/(double)Vi.Count());
            return G;
        }

        private void initArray(double[] Vi)
        {
            for (int i = 0; i < Vi.Count(); i++)
            {
                Vi[i] = 1;
            }
        }
    }
}
